import { onBeforeMount, onBeforeUnmount, reactive, ref } from 'vue'

/** 点击空白清空
 * @param {HTMLElement} dom
 * @param {Boolean|Function} show
 */
type ClickBlankType = () => HTMLElement | undefined

export const useClickBlankHidden = (domFn: ClickBlankType | ClickBlankType[], fn: () => void) => {
  const handleBlankClick = (ev: MouseEvent): void => {
    domFn = [domFn].flat(Infinity) as ClickBlankType[]
    const off = domFn.every((item) => {
      const dom = item()
      if (!dom) return true
      return dom && !dom.contains(ev.target as Node)
    })
    if (off) fn()
  }
  onBeforeMount(() => {
    document.addEventListener('mousedown', handleBlankClick, true)
  })
  onBeforeUnmount(() => {
    document.removeEventListener('mousedown', handleBlankClick, true)
  })
}

export interface IUseDragInfo {
  disX: number
  disY: number
  start: boolean
  x: number
  y: number
  width: number
  height: number
  proportionX: number
  proportionY: number
}

export interface IUseDragParams {
  default?: Partial<IUseDragInfo>
  click?: (ev: MouseEvent, proportion: { proportionX: number; proportionY: number }) => void
  down?: (ev: MouseEvent) => void
  move?: (ev: MouseEvent, proportion: { proportionX: number; proportionY: number }) => void
  up?: (ev: MouseEvent, proportion: { proportionX: number; proportionY: number }) => void
}

export const  useDragHook = (handleData?: IUseDragParams) => {
  const dragDom = ref<HTMLElement | null>()
  const dragInfo = reactive<IUseDragInfo>({
    start: false,
    x: 0,
    y: 0,
    disX: handleData?.default?.disX || 0,
    disY: handleData?.default?.disY || 0,
    width: handleData?.default?.width || 0,
    height: handleData?.default?.height || 0,
    proportionX: 0,
    proportionY: 0
  })

  const handleClick = (ev: MouseEvent) => {
    if (!dragDom.value) return
    const { left, top, width, height } = dragDom.value.getBoundingClientRect()
    const lineWidth = ev.x - left
    const lineHeight = height - (ev.y - top)
    dragInfo.width = lineWidth > width - dragInfo.disX ? width - dragInfo.disX : lineWidth
    dragInfo.height = lineHeight > height - dragInfo.disY ? height - dragInfo.disY : lineHeight
    if (typeof handleData?.click === 'function') {
      handleData.click(ev, {
        proportionX: dragInfo.width / (width - dragInfo.disX),
        proportionY: dragInfo.height / (height - dragInfo.disY)
      })
    }
  }

  const handleMousemove = (ev: MouseEvent) => {
    if (!dragInfo.start || !dragDom.value) return
    const { width, height } = dragDom.value.getBoundingClientRect()
    const lineWidth = ev.x - dragInfo.x
    const lineHeight = -(ev.y - dragInfo.y)
    dragInfo.width = lineWidth > width - dragInfo.disX ? width - dragInfo.disX : lineWidth <= 0 ? 0 : lineWidth
    dragInfo.height = lineHeight > height - dragInfo.disY ? height - dragInfo.disY : lineHeight <= 0 ? 0 : lineHeight
    if (typeof handleData?.move === 'function') {
      handleData.move(ev, {
        proportionX: dragInfo.width / (width - dragInfo.disX),
        proportionY: dragInfo.height / (height - dragInfo.disY)
      })
    }
  }
  const handleMouseup = (ev: MouseEvent) => {
    if (!dragDom.value) return
    dragInfo.start = false
    const { width, height } = dragDom.value.getBoundingClientRect()
    if (typeof handleData?.up === 'function') {
      handleData?.up(ev, { proportionX: dragInfo.width / width, proportionY: dragInfo.height / height })
    }
    document.removeEventListener('mousemove', handleMousemove)
    document.removeEventListener('mouseup', handleMouseup)
  }
  const handleMousedown = (ev: MouseEvent) => {
    dragInfo.start = true
    dragInfo.x = ev.x - dragInfo.width
    dragInfo.y = ev.y + dragInfo.height
    if (typeof handleData?.down === 'function') handleData?.down(ev)
    document.documentElement.addEventListener('mousemove', handleMousemove)
    document.documentElement.addEventListener('mouseup', handleMouseup)
  }

  return {
    dragDom,
    dragInfo,
    handleClick,
    handleMousedown
  }
}
